using System;
using System.Reflection;

namespace NMollom {
    /// <summary>
    /// The attribute to tag an enum value to specify its Mollom representation.
    /// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class MollomTypeAttribute : Attribute {
        private readonly string type = "";

        public MollomTypeAttribute(string type) {
            if (string.IsNullOrEmpty(type))
                throw new ArgumentNullException("type");
            this.type = type;
        }

        public string Type {
            get { return type; }
        }
    }

    /// <summary>
    /// Converts mollom type specifiers to the internal format and vice versa.
    /// </summary>
    public class MollomTypeConvertor {
        public static string ToMollomStatisticType(StatisticType type) {
            return ToMollom(type);
        }

        public static StatisticType FromMollomStatisticType(string type) {
            return FromMollom<StatisticType>(type);
        }

        public static string ToMollomFeedbackType(FeedbackType type) {
            return ToMollom(type);
        }

        public static FeedbackType FromMollomFeedbackType(string type) {
            return FromMollom<FeedbackType>(type);
        }

        #region This does all the work

        private static string ToMollom(Enum type) {
            foreach (FieldInfo field in type.GetType().GetFields(BindingFlags.Public | BindingFlags.Static)) {
                if (field.FieldType == type.GetType() && Convert.ToInt32(field.GetRawConstantValue()) == Convert.ToInt32(type)) {
                    object[] attr = field.GetCustomAttributes(typeof (MollomTypeAttribute), false);
                    if (attr.Length > 0) {
                        return ((MollomTypeAttribute) attr[0]).Type;
                    }
                }
            }

            throw new ArgumentException(string.Concat("The specified ", type.GetType().Name, " is unknown."), "type");
        }

        private static T FromMollom<T>(string type) {
            foreach (FieldInfo field in typeof (T).GetFields()) {
                object[] attr = field.GetCustomAttributes(typeof (MollomTypeAttribute), false);
                if (attr.Length > 0 && string.Compare(((MollomTypeAttribute) attr[0]).Type, type, true) == 0) {
                    return (T) field.GetRawConstantValue();
                }
            }

            throw new ArgumentException(
                string.Concat("The specified type value can't be mapped to a ", typeof (T).Name, "."), "type");
        }

        #endregion
    }
}